package org.test4j.mock.stub;

import g_cglib.net.sf.cglib.proxy.MethodInterceptor;
import g_cglib.net.sf.cglib.proxy.MethodProxy;
import org.test4j.mock.Invocation;
import org.test4j.mock.faking.FakeInvoker;
import org.test4j.mock.faking.meta.FakeMethod;
import org.test4j.mock.faking.meta.FakeStates;
import org.test4j.mock.faking.meta.MethodId;

import java.lang.reflect.Method;

public class FakeInterceptor implements MethodInterceptor {
    private Class aClass;

    public FakeInterceptor(Class aClass) {
        this.aClass = aClass;
    }

    @Override
    public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) {
        FakeMethod fakeMethod = FakeStates.getLastMethod(new MethodId(this.aClass, method));
        if (fakeMethod == null) {
            throw new AssertionError("Method not implemented and not mocked.");
        } else if (fakeMethod.isProceeding()) {
            throw new RuntimeException("the abstract method can't be reentry again.");
        }
        FakeInvoker invoker = new FakeInvoker(target, fakeMethod, this.aClass, method, args) {
            @Override
            protected Invocation newInvocation() {
                return new StubFakeInvocation(target, args, fakeMethod.getTimesInvoked());
            }
        };
        return invoker.callFakeMethod();
    }
}